﻿#region Header

/*
Remote views based on linq
By

Pascal Hauser 
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

and

Raphael Gfeller
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

*/

#endregion

#region Usings

using System;
using System.Reflection;
using Sebarf.Core.Interfaces;
using Sebarf.Diagnostics.Interfaces;
using Sebarf.Services.Interfaces;
using Sebarf.Utils.Interfaces;

#endregion

namespace Sebarf.Services.Impl {
	/// <summary>
	/// Description of the class
	/// </summary>
	public class ResolveDependenciesRequestHandler : RequestHandler<ResolveDependenciesRequest> {
		public IObjectHierarchyFlattenerService ObjectHierarchyFlattenerService { get; set; }

		#region Public Methods

		protected override object OnProcessRequest(ResolveDependenciesRequest request, IServiceLocatorService serviceLocator) {
			Check.AssertException(serviceLocator.IsServiceAvailable<IDiagnosticsServiceLocatorService>(),
								   "IDiagnosticsServiceLocatorService has to be available");
			var service = serviceLocator.GetRegisteredService<IDiagnosticsServiceLocatorService>();
			IServiceImpl[] services = service.GetAllRegisteredServices<IServiceImpl>();
			if (ObjectHierarchyFlattenerService == null) {
				Check.AssertException(serviceLocator.IsServiceAvailable<IObjectHierarchyFlattenerService>(),
									   "requires IObjectHierarchyFlattenerService");
				ObjectHierarchyFlattenerService = serviceLocator.GetRegisteredService<IObjectHierarchyFlattenerService>();
			}

			ResolveReferences(request.ResolveMyReferences, services);

			return true;
		}

		#endregion

		private void ResolveReferences(object obj, IService[] services) {
			if (obj == null || obj is ValueType) {
				return;
			}
			// inject services
			foreach (PropertyInfo property in ObjectHierarchyFlattenerService.GetAllProperties(obj.GetType())) {
				foreach (Attribute attribute in property.GetCustomAttributes(true)) {
					if (attribute is ServiceRequest) {
						object serviceToInject = GetRegisteredService(property.PropertyType, services);
						if (serviceToInject == null && !(attribute as ServiceRequest).IsOptional) {
							Check.ArgumentNotNull(serviceToInject,
												   "service not found:" + property.PropertyType + ", has been requested by " + obj.GetType());
						}
						property.SetValue(obj, serviceToInject, null);
					}
				}
			}
		}

		private object GetRegisteredService(Type t, IService[] services) {
			foreach (IService service in services) {
				if (t.IsAssignableFrom(service.GetType())) {
					return service;
				}
			}
			return null;
		}
	}
}